package cat.sun.graphics;

import cat.sun.R;
import cat.sun.activities.Game;
import cat.sun.activities.Main;
import cat.sun.logic.GameManager;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.os.Bundle;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.Scroller;

public class MyView extends View 
{	
	private ScaleGestureDetector mScaleDetector;
	private final GestureDetector detector;
	private float mScaleFactor = 1f;	
	private int viewHeight,viewWidth;
	private int bmpWidth, bmpHeight; 
	private boolean firstDraw = true;	
	private final Scroller scroller;
	private GameManager gameManager;
	private FieldBitmapMaker bitmapMaker;
	private Vibrator vibrator;
	private boolean hasToVibrate; 
	private Bundle loadState = null;
		
	public MyView(Context context, AttributeSet attrs)
	{
		super(context, attrs);

		mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
		detector=new GestureDetector(context, new MyGestureListener());			
		
		setHorizontalScrollBarEnabled(true);
        setVerticalScrollBarEnabled(true);
        TypedArray a = context.obtainStyledAttributes(R.styleable.View);
        initializeScrollbars(a);
        a.recycle();       
        
        vibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
        
        mScaleFactor = getContext().getSharedPreferences(Main.OPTIONS, 0).getFloat(Main.ZOOM, 0.5f);
        
        scroller = new Scroller(context);
        
        this.mScaleFactor = getContext().getSharedPreferences(Game.bundleName, 0).getFloat(Game.scaleSave, 1f);
	}

	public float getMyScaleFactor()
	{
		return this.mScaleFactor;
	}
		
	public void setStartUp(GameManager gameManager, Boolean hasToVibrate, FieldBitmapMaker fieldBitmapMaker)
	{
		this.gameManager = gameManager;
		this.bitmapMaker = fieldBitmapMaker;
		bmpWidth = this.bitmapMaker.getFieldWidth();
		bmpHeight = this.bitmapMaker.getFieldHeight();
		scrollTo(0, 0);
		ScrollToCenter();
		this.hasToVibrate = hasToVibrate;
	}
			
	@Override
	public void computeScroll()
	{
	    if (scroller.computeScrollOffset())
	    {
	       int oldX = getScrollX();
	       int oldY = getScrollY();
	       int x = scroller.getCurrX();
	       int y = scroller.getCurrY();
	       if (this.viewHeight > this.bmpHeight*mScaleFactor) y = oldY;
	       if (this.viewWidth > this.bmpWidth*mScaleFactor) x = oldX;
	       scrollTo(x, y);
	       if (oldX != getScrollX() || oldY != getScrollY())
	       {
	          onScrollChanged(getScrollX(), getScrollY(), oldX, oldY);
	       }
	       ScrollToCenter();
           postInvalidate();
        }
    }
	
	@Override
	protected int computeHorizontalScrollRange()
	{
	    return (int)(this.bmpWidth*mScaleFactor);
	}

	@Override
	protected int computeVerticalScrollRange()
	{
	    return (int)(this.bmpHeight*mScaleFactor);
	}
	
	private void ScrollToCenter()
	{
		int ScrollX = 0,ScrollY = 0;
		if (this.viewHeight > this.bmpHeight*mScaleFactor)
		{			
			ScrollY = -(int)((this.viewHeight-this.bmpHeight*mScaleFactor)/2);
			scrollTo(getScrollX(), ScrollY);
		}	
		if (this.viewWidth > this.bmpWidth*mScaleFactor)
		{			
			ScrollX = -(int)((this.viewWidth-this.bmpWidth*mScaleFactor)/2);
			scrollTo(ScrollX, getScrollY());
		}	
		invalidate();
	}	
	
	public void Update()
	{
		invalidate();
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
	{
	    super.onMeasure(widthMeasureSpec, heightMeasureSpec);	   
	    int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
	    int parentHeight = MeasureSpec.getSize(heightMeasureSpec); 
	    this.viewHeight = parentHeight;
	    this.viewWidth = parentWidth;
	    this.setMeasuredDimension(parentWidth, parentHeight);	    
	    if (firstDraw) 
	    {
	    	if (this.viewHeight > this.bmpHeight*mScaleFactor || this.viewWidth > this.bmpWidth*mScaleFactor) ScrollToCenter();
	    	firstDraw = false;
	    	if (loadState != null)
	    	{
	    		scrollTo(0, 0);		
	    		mScaleFactor = loadState.getFloat("viewScaleFactor");		
	    		
	    		int moveX = (int)(loadState.getFloat("centerX")*mScaleFactor - viewWidth/2);
	    		int moveY = (int)(loadState.getFloat("centerY")*mScaleFactor - viewHeight/2);

	    		if (bmpWidth*mScaleFactor > viewWidth)
	    		{
	    			scrollBy(Math.max(0,Math.min( moveX ,(int)(bmpWidth*mScaleFactor - viewWidth))) , 0);			
	    		}
	    		if (bmpHeight*mScaleFactor > viewHeight)
	    		{
	    			scrollBy( 0, Math.max( Math.min(moveY ,(int)(bmpHeight*mScaleFactor - viewHeight)) ,0)  );
	    		} 
	    		ScrollToCenter();
	    		loadState = null;
	    	}
	    }
	}	

	@Override
	public boolean onTouchEvent(MotionEvent ev) 
	{
		detector.onTouchEvent(ev);
	    mScaleDetector.onTouchEvent(ev);
	    if ((ev.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN)
	    {
	       if (!scroller.isFinished()) scroller.abortAnimation();
	    }
	    return true;
	}
			
	public void getSaveInstance(Bundle save)
	{
		save.putFloat("viewScaleFactor", mScaleFactor);
		
    	float x = (float)((viewWidth/2+getScrollX()))/mScaleFactor;
    	float y = (float)((viewHeight/2+getScrollY()))/mScaleFactor; 

		save.putFloat("centerX",x);
		save.putFloat("centerY",y);
	
	}
	
	public void setSavedState(Bundle save)
	{
		this.loadState = save;
	}

	@Override
	public void onDraw(Canvas canvas) 
	{
		//Log.v("SUN","In on Draw");
		
	    super.onDraw(canvas);

	    canvas.save();
	    canvas.scale(mScaleFactor, mScaleFactor);
	    
	    this.bitmapMaker.addFieldOnCanvas(canvas, gameManager.getFiled(), 0, 0);
	    canvas.restore();
	}

	private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener 
	{
		public boolean onScale(ScaleGestureDetector scaleGestureDetector) 
		{
            float scaleFactor=scaleGestureDetector.getScaleFactor();
            float focusX=scaleGestureDetector.getFocusX();
            float focusY=scaleGestureDetector.getFocusY(); 
           
            mScaleFactor *= scaleGestureDetector.getScaleFactor();
            
            if (mScaleFactor>1) {mScaleFactor = 1f; ScrollToCenter(); return true; }
            if (mScaleFactor<0.25){ mScaleFactor = 0.25f;}// ScrollToCenter(); return true; }
            
            if (viewWidth <= bmpWidth*mScaleFactor)
            {
            	int scrollX=(int)((getScrollX()+focusX)*scaleFactor-focusX);
            	scrollTo((int)Math.min(Math.max(scrollX,0),bmpWidth*mScaleFactor-viewWidth),getScrollY());
            }            
            else ScrollToCenter();
            
            if (viewHeight <= bmpHeight*mScaleFactor)
            {
            	int scrollY=(int)((getScrollY()+focusY)*scaleFactor-focusY);
            	scrollTo(getScrollX(),(int)Math.min(Math.max(scrollY,0),bmpHeight*mScaleFactor-viewHeight));
            }
            else ScrollToCenter();
            
            awakenScrollBars(); 
            invalidate();
            return true;
        }
	}
	
	private class MyGestureListener extends GestureDetector.SimpleOnGestureListener
    {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
        {        	
        	if (viewWidth <= bmpWidth*mScaleFactor)
        	{
        		if (getScrollX()+distanceX < 0 ) scrollTo(0,getScrollY()); else
        		if (getScrollX()+distanceX > bmpWidth*mScaleFactor-viewWidth) scrollTo((int)(bmpWidth*mScaleFactor)-viewWidth,getScrollY()); 
        		else scrollBy((int)distanceX, 0);           
        	}
            if (viewHeight <= bmpHeight*mScaleFactor)
            {
            	if (getScrollY()+distanceY < 0 ) scrollTo(getScrollX(),0); else
            	if (getScrollY()+distanceY > bmpHeight*mScaleFactor-viewHeight) scrollTo(getScrollX(),(int)(bmpHeight*mScaleFactor)-viewHeight); 
        		else scrollBy(0, (int)distanceY);
            }
            awakenScrollBars();
            invalidate();
            return true;
        }
        
        @Override
        public boolean onDoubleTapEvent(MotionEvent e)
        {        	
        	float x = (e.getX()+getScrollX())/mScaleFactor;
	    	float y = (e.getY()+getScrollY())/mScaleFactor; 
	    	
	    	int fieldX = bitmapMaker.getCellNumber(x);
	    	int fieldY = bitmapMaker.getCellNumber(y);
   	
	    	if (x>=0 && y>=0 && x<=bmpWidth && y<=bmpHeight)
	    	{    	           	
	    		gameManager.DoubleTouch(fieldX, fieldY);
	    		invalidate();	    		
	    	}
	    	return true;
        }
        
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
        {
        	scroller.fling(getScrollX(), getScrollY(), -(int)velocityX, -(int)velocityY, 0, (int)(bmpWidth*mScaleFactor)-viewWidth, 0, (int)(bmpHeight*mScaleFactor)-viewHeight);
        	awakenScrollBars(scroller.getDuration());  
        	ScrollToCenter();
            return true;
        }
        
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) 
        {
        	if ((e.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN)
    	    {
    	       if (!scroller.isFinished()) scroller.abortAnimation();
    	       else
    	       {    	    	   
    	    	   float x = (e.getX()+getScrollX())/mScaleFactor;
    	    	   float y = (e.getY()+getScrollY())/mScaleFactor; 
    	    	   
    	    	   int fieldX = bitmapMaker.getCellNumber(x);
    		    	int fieldY = bitmapMaker.getCellNumber(y);    	   	
    	    	   
    	    	   if (x>=0 && y>=0 && x<=bmpWidth && y<=bmpHeight)
    	    	   {    	           	
    	    		   gameManager.MakeMove(fieldX,fieldY,true);
        	    	   invalidate();        	    	   
    	    	   }
    	       }
    	    }
        	return true;
        }
        
        @Override
        public void onLongPress(MotionEvent e) 
        {
        	float x = (e.getX()+getScrollX())/mScaleFactor;
	    	float y = (e.getY()+getScrollY())/mScaleFactor; 
	    	if (hasToVibrate) vibrator.vibrate(40);
	    	int fieldX = bitmapMaker.getCellNumber(x);
	    	int fieldY = bitmapMaker.getCellNumber(y);  	
	    	if (x>=0 && y>=0 && x<=bmpWidth && y<=bmpHeight) gameManager.Checked(fieldX, fieldY);
	    	invalidate();    	
        }
    }
	
}
